﻿namespace SADev.SharePointHolidayLoader
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Text.RegularExpressions;
    using SharePointListService.SADev.SharePoint;

    class HolidayCalendar
    {
        private readonly CountryList countries = new CountryList();
        private int eventCount;

        public Exception LastException { get; private set; }

        public Country this[int index]
        {
            get
            {
                return countries[index];
            }
        }

        public Country this[string name]
        {
            get
            {
                return countries[name];
            }
        }

        public CountryList Countries
        {
            get
            {
                return countries;
            }
        }

        internal static HolidayCalendar Load(string fileName)
        {
            var result = new HolidayCalendar();
            var counter = 0;
            Regex countryParserRegEx = new Regex(@"\[(?<Country>.+)\]\s(?<ID>\d+)");
            Regex eventParserRegEx = new Regex(@"(?<Event>[\w\s\p{P}^,]+)\s*,\s*(?<Date>\d{4}/\d{1,2}/\d{1,2})");
            DateTime minDate = new DateTime(1900, 1, 1);
            DateTime maxDate = new DateTime(8900, 12, 31);

            var lines = from l in File.ReadAllLines(fileName)
                        where !string.IsNullOrWhiteSpace(l)
                        select l.Trim();


            Country country = null;

            foreach (var line in lines)
            {
                if (line.StartsWith("["))
                {
                    var match = countryParserRegEx.Match(line);
                    if (!match.Success)
                    {
                        continue;
                    }

                    if (country != null)
                    {
                        result.countries.Add(country);
                    }

                    var name = match.Groups["Country"].Value;
                    var id = Convert.ToInt32(match.Groups["ID"].Value);

                    country = new Country(name, id);
                    continue;
                }
                else
                {
                    if (country == null)
                    {
                        continue;
                    }

                    var match = eventParserRegEx.Match(line);
                    if (!match.Success)
                    {
                        continue;
                    }

                    var name = match.Groups["Event"].Value;
                    DateTime date;
                    try
                    {
                        date = DateTime.ParseExact(match.Groups["Date"].Value, "yyyy/M/d", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AllowWhiteSpaces);
                    }
                    catch (FormatException err)
                    {
                        if (err.Message.Equals("The DateTime represented by the string is not supported in calendar System.Globalization.GregorianCalendar."))
                        {
                            continue;
                        }

                        throw;
                    }

                    if (date >= minDate && date <= maxDate)
                    {
                        country.AddHoliday(name, date);
                    }

                    counter++;
                }
            }

            if (country != null && country.Holidays.Count() > 0)
            {
                result.countries.Add(country);
            }

            result.eventCount = counter;

            if (!result.countries.Any())
            {
                throw new Exception("No countries");
            }

            return result;
        }

        internal bool Publish(Uri sharePointUri, string calendarName, NetworkCredential credential, string country, Action<int> progressUpdate = null)
        {
            var sharePointList = new SharePointListService.SADev.SharePoint.Lists();
            sharePointList.Url = string.Format(CultureInfo.CurrentCulture, "{0}/_vti_bin/lists.asmx", sharePointUri);
            if (credential != null)
            {
                sharePointList.Credentials = credential;
            }
            else
            {
                sharePointList.UseDefaultCredentials = true;
            }

            try
            {
                var listViewNode = sharePointList.GetListAndView(calendarName, string.Empty);

                var listId = listViewNode.ChildNodes[0].Attributes["Name"].Value;
                var viewId = listViewNode.ChildNodes[1].Attributes["Name"].Value;
                var batch = SharePointHelpers.CreateBatch(viewId);
                var counter = 0;
                foreach (var holiday in countries[country].Holidays)
                {
                    var fields = new Dictionary<string, object>();
                    fields.Add("Title", holiday.Event);
                    fields.Add("Location", country);
                    fields.Add("fAllDayEvent", true);
                    fields.Add("EventDate", holiday.Date.ToSharePointDateTimeFormat());
                    fields.Add("EndDate", holiday.Date.ToSharePointDateTimeFormat());
                    fields.Add("Category", "Holiday");
                    batch.AddNewItemsToBatch(fields);

                    counter++;
                    if (progressUpdate != null)
                    {
                        progressUpdate(counter);
                    }
                }

                batch.Insert(sharePointList, listId);
                return true;
            }
            catch (Exception err)
            {
                this.LastException = err;
                return false;
            }
        }

        public int EventCount
        {
            get
            {
                return eventCount;
            }
        }
    }
}
